package edu.harvard.eecs.airg.coloredtrails.server;

import org.apache.log4j.Logger;

import javax.jms.*;
import java.util.Vector;

import edu.harvard.eecs.airg.coloredtrails.shared.types.GameConfig;
import edu.harvard.eecs.airg.coloredtrails.shared.types.PlayerStatus;
import edu.harvard.eecs.airg.coloredtrails.shared.types.GameStatus;
import edu.harvard.eecs.airg.coloredtrails.shared.CTClassLoader;

/**
 * Created by IntelliJ IDEA.
 * User: rani
 * Date: Feb 6, 2008
 * Time: 4:09:40 PM
 */
public class CtrlCommands {

    public static final String LIST_GAMES = "LIST_GAMES";
    public static final String LIST_CONFIGURATIONS = "LIST_CONFIGURATIONS";
    public static final String LIST_PLAYERS = "LIST_PLAYERS";
    public static final String GET_LOG = "GET_LOG";
    public static final String NEW_GAME = "NEW_GAME";
    public static final String ADD_CONFIGURATION = "ADD_CONFIGURATION";
    public static final String NEW_GAME_REPLY = "NEW_GAME_REPLY";
    public static final String ADD_CONFIGURATION_REPLY = "ADD_CONFIGURATION_REPLY";

    public static final String MSG_NAME = "MSG_NAME";
    public static final String REPLY = "REPLY";
    public static final String MSG_TYPE = "MSG_TYPE";
    public static final String ADMIN_CLIENT = "ADMIN_CLIENT";
    public static final String CONFIGCLASS_NAME = "CONFIGCLASS_NAME";
    public static final String CONFIGCLASS = "CONFIGCLASS";

    private Session session = null;
    private MessageProducer producer = null;

    public CtrlCommands(Session session, MessageProducer producer) {
        this.session = session;
        this.producer = producer;
    }

    public void setConfigClass(BytesMessage msg) {
        try {
            log.info("Received message from admin: SET_CONFIGURATION");
            configClass = new byte[(int) msg.getBodyLength()];
            msg.readBytes(this.configClass);
        } catch (JMSException e) {
            log.fatal("Error receiving message:" + e);
        }
    }

    private byte[] configClass = null;

    private static Logger log = Logger.getRootLogger();

    public void handleMessage(Message msg) {
        Message reply = null;
        try {
            String msgName = msg.getStringProperty(ColoredTrailsServer.COMMAND);
            log.info("Received message from controller:" + msgName);
            if (msgName.equals(ADD_CONFIGURATION)) {
                reply = addConfiguration(msg.getStringProperty(CONFIGCLASS_NAME));
            } else if (msgName.equals(NEW_GAME)) {
                String[] playerStrings = msg.getStringProperty(LIST_PLAYERS).split("\\s");
                int[] players = new int[playerStrings.length];
                for (int i = 0; i < playerStrings.length; i++) {
                    players[i] = Integer.parseInt(playerStrings[i]);
                }
                reply = newGame(msg.getStringProperty(CONFIGCLASS_NAME), players);
            }
        } catch (JMSException e) {
            log.fatal("Error receiving message from controller:" + e);
        }
        if (reply == null){
            log.debug("reply is null");
            return;
        }

        try {

            reply.setStringProperty(ColoredTrailsServer.MSGTYPE, ADMIN_CLIENT);
            producer.send(reply);
            log.info("Sending reply to controller: " + reply.getStringProperty(MSG_NAME));
        } catch (JMSException e) {
            log.fatal("Error sending reply to controller:" + e);
        }

    }


    /**
     * Add a configuration (described by a class) to the server.
     *
     * @param name The name of the configuration being uploaded.
     * @return Whether the addition of the configuration was successful.
     */
    public Message addConfiguration(String name) {
        if (configClass == null) {
            log.fatal("Error adding configuration:");
            return null;
        }
        ServerData data = ServerData.getInstance();
        CTClassLoader ct = new CTClassLoader();
        ct.defClass(name, configClass);
        boolean success = false;
        TextMessage reply = null;

        try {
            Class c = ct.loadClass(name);
            data.addConfiguration(new GameConfig(name, c, configClass));

            // reset configClass for next time
            configClass = null;
            log.debug("Administrator: adding configuration file [" + name + "] class name: " + c.getName());
            success = true;

        } catch (Exception e) {
            e.printStackTrace();
        }
        try {
            reply = session.createTextMessage();
            reply.setStringProperty(MSG_NAME, ADD_CONFIGURATION_REPLY);
            reply.setBooleanProperty(REPLY, success);

        } catch (JMSException e) {
            log.fatal("Error adding configuration:" + e);
        }
        return reply;
    }

    /**
     * Create a new game with the designated players, configuration name,
     * and start the game.
     *
     * @param configName The name of the configuration details class
     *                   which will define this game.
     * @param playerids  A list of player ids for this game.
     * @return The id of the created game.
     */
    public Message newGame(String configName, int[] playerids) {

        log.debug("Administrator: newGame configName = [" + configName + "] ");
        TextMessage reply = null;
        Vector<PlayerStatus> v = new Vector<PlayerStatus>();
        for (int playerid : playerids) {
            log.debug("Administrator: newGame adding Player: [" + playerid + "]");
            v.add(new PlayerStatus(playerid));
        }
        int newGame = ServerData.getInstance().addNewGame(configName, v);
        try {
            reply = session.createTextMessage();
            reply.setStringProperty(MSG_NAME, NEW_GAME);
            reply.setIntProperty(NEW_GAME, newGame);

        } catch (JMSException e) {
            log.fatal("Error adding configuration:" + e);
        }
        return reply;
    }

    public void sendGameStartMessage(GameStatus game) {
        try {
            log.debug("sendGameStart to controller");
            ObjectMessage gameStartMsg = session.createObjectMessage();
            gameStartMsg.setObject(game);
            log.debug("sending game id = " + game.getGameId());
            gameStartMsg.setStringProperty(ColoredTrailsServer.MSGTYPE, CtrlCommands.ADMIN_CLIENT);
            gameStartMsg.setStringProperty(MSG_NAME, ColoredTrailsServer.GAMESTART);
            gameStartMsg.setStringProperty(ColoredTrailsServer.OBJECTTYPE, ColoredTrailsServer.GAMESTART);

            producer.send(gameStartMsg);
        }
        catch (JMSException e) {
            log.fatal("Error sending game start message to controller:" + e);
        }

    }    


}


